package com.xiguanlezz.cn.client.naming.event;

import com.xiguanlezz.cn.api.naming.listener.AbstractEventListener;
import com.xiguanlezz.cn.api.naming.listener.EventListener;
import com.xiguanlezz.cn.api.naming.listener.NamingEvent;
import com.xiguanlezz.cn.api.naming.pojo.ServiceInfo;
import com.xiguanlezz.cn.api.naming.utils.NamingUtils;
import com.xiguanlezz.cn.common.notify.Event;
import com.xiguanlezz.cn.common.notify.listener.Subscriber;
import org.apache.commons.collections.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/11/28 17:52
 * @Description：服务实例事件订阅器
 */
public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {

    // 通知事件唯一标识，这个唯一标识是从NacosNamingService中传递过来的
    // 一个NacosNamingService对应了一个eventScope，假如一个服务器中存在多个NacosNamingService，凭借这个标识就可以分隔各自的服务实例变更事件
    private final String eventScope;

    // 存放用户定义的事件监听器
    // 其中key就是监听的具体服务名，value就是对应的监听器集合
    private final ConcurrentMap<String, ConcurrentSkipListSet<EventListener>> listenerMap = new ConcurrentHashMap<>();


    public InstancesChangeNotifier(String eventScope) {
        this.eventScope = eventScope;
    }

    /**
     * 注册某个服务的事件监听器
     */
    public void registerListener(String serviceName, String groupName, String clusters, EventListener listener) {
        // 获取服务的key
        String serviceKey = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
        // 将监听器加入map中
        ConcurrentSkipListSet<EventListener> eventListeners = listenerMap.computeIfAbsent(serviceKey, keyInner -> new ConcurrentSkipListSet<>());
        eventListeners.add(listener);
    }

    /**
     * 注销某个服务的事件监听器
     */
    public void deregisterListener(String serviceName, String groupName, String clusters, EventListener listener) {
        // 获取服务的key
        String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
        // 删除map中的监听器
        ConcurrentSkipListSet<EventListener> eventListeners = listenerMap.get(key);
        if (CollectionUtils.isEmpty(eventListeners)) {
            listenerMap.remove(key);
            return;
        }
        eventListeners.remove(listener);
        if (CollectionUtils.isEmpty(eventListeners)) {
            listenerMap.remove(key);
        }
    }

    /**
     * 判断某个服务是否注册了监听器
     */
    public boolean isSubscribed(String serviceName, String groupName, String clusters) {
        String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
        ConcurrentSkipListSet<EventListener> eventListeners = listenerMap.get(key);
        return CollectionUtils.isNotEmpty(eventListeners);
    }

    /**
     * 得到所有被监听的ServiceInfo的信息
     */
    public List<ServiceInfo> getSubscribeServices() {
        List<ServiceInfo> serviceInfos = new ArrayList<>();
        for (String key : listenerMap.keySet()) {
            serviceInfos.add(ServiceInfo.fromKey(key));
        }
        return serviceInfos;
    }

    @Override
    public void onEvent(InstancesChangeEvent event) {
        // 获取服务的key
        String key = ServiceInfo.getKey(NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName()), event.getClusters());
        ConcurrentSkipListSet<EventListener> eventListeners = listenerMap.get(key);
        if (CollectionUtils.isEmpty(eventListeners)) {
            return;
        }
        //遍历集合
        for (final EventListener listener : eventListeners) {
            // 类型转换
            NamingEvent namingEvent = instancesChangeEvent2NamingEvent(event);
            // 如果AbstractEventListener且回调事件执行线程池不为空，则用该线程池执行回调接口，不然就是当前线程执行
            if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {
                ((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(namingEvent));
            } else {
                //这里就是用户没有在监听器中定义执行器的逻辑，直接由调用当前onEvent方法的线程执行监听器的回调方法
                listener.onEvent(namingEvent);
            }
        }
    }

    private NamingEvent instancesChangeEvent2NamingEvent(InstancesChangeEvent instancesChangeEvent) {
        return new NamingEvent(
                instancesChangeEvent.getServiceName(),
                instancesChangeEvent.getGroupName(),
                instancesChangeEvent.getClusters(),
                instancesChangeEvent.getHosts()
        );
    }

    /**
     * 订阅的事件类型
     */
    @Override
    public Class<? extends Event> subscribeType() {
        return InstancesChangeEvent.class;
    }
}
